package org.nobody.mallb2c.mallauth.controller;

import com.alibaba.fastjson.TypeReference;
import com.netflix.client.ClientException;
import org.nobody.common.constant.AuthServerConstant;
import org.nobody.common.exception.ResultCodeEnum;
import org.nobody.common.utils.R;
import org.nobody.common.vo.MemberRespVo;
import org.nobody.mallb2c.mallauth.feign.MemberFeignService;
import org.nobody.mallb2c.mallauth.feign.ThirdPartFeignService;
import org.nobody.mallb2c.mallauth.vo.UserLoginVo;
import org.nobody.mallb2c.mallauth.vo.UserRegistVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 3489309323@qq.com
 * @create 2020-09-16-19:08
 */
@Controller
public class LoginController {

  /**
   * 如果是发送一个请求直接跳转到一个页面
   * 我们可以通过使用 SpringMVC viewcontroller 将请求和页面映射过来
   * 而不是像↓面这样写
   */
//  @GetMapping("/login.html")
//  public String loginPage(){
//    return "login";
//  }
//
//  @GetMapping("/reg.html")
//  public String regPage(){
//    return "reg";
//  }

  @Autowired
  ThirdPartFeignService thirdPartFeignService;

  @Autowired
  StringRedisTemplate redisTemplate;

  @Autowired
  MemberFeignService memberFeignService;

  @ResponseBody
  @GetMapping("/sms/sendCode")
  public R sendCode(@RequestParam("phone") String phone) throws ClientException {

    String redisSmsCode = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);
    if (!StringUtils.isEmpty(redisSmsCode)) {
      long limit = Long.parseLong(redisSmsCode.split("_")[1]);
      if (System.currentTimeMillis() - limit < 60000) {
        //60s内不能再发送
        return R.error(ResultCodeEnum.SMS_CODE_EXCEPTION.getCode(),ResultCodeEnum.SMS_CODE_EXCEPTION.getMsg());
      }
    }

    String smsCode = UUID.randomUUID().toString().substring(0, 5);
    redisSmsCode =  smsCode + "_" + System.currentTimeMillis();

    //redis缓存验证码,防止同一个phone在60秒内再次发送验证码
    redisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone, redisSmsCode, 10, TimeUnit.MINUTES);

    thirdPartFeignService.sendCode(phone, smsCode);
    return R.ok();
  }

  @PostMapping("/regist")
  public String regist(@Valid UserRegistVo vo, BindingResult result, /*Model model*/RedirectAttributes redirectAttributes){
    //表单校验出错,转发到注册页
    if (result.hasErrors()) {

      Map<String, String> erros = result.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
      //model.addAttribute("errors", erros);
      //重定向的话 要使用如下方式传递数据
      //原理是session,只要跳到下一个页面取出这个数据以后,session就会被删掉
      //todo 分布式
      redirectAttributes.addFlashAttribute("errors", erros);

      //return "reg";//会拼串

      //会从MallWebConfig映射中去找 ---> return "reg" ---> 拼串
      //但路径映射默认都是get方式才能访问的
      //故这里这样转发会报错（post请求转给了get请求）
      //return "forward:/reg.html";

      //防止表单重复提交 使用重定向的方式
      //return "redirect:/reg.html";
      //↑ 但这样做(:/reg.html)不是按照域名来跳的 是按照端口来跳

      //最终选择以下方式来重定向
      return "redirect:http://auth.mall.com/reg.html";
    }

    //真正注册
    //1、 校验验证码
    String code = vo.getCode();
    String redisCode = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
    if (!StringUtils.isEmpty(redisCode) && code.equals(redisCode.split("_")[0])) { //说明验证成功 可以进行保存
      //删除验证码
      redisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
      //
      R r = memberFeignService.regist(vo);
      if (r.getCode() == 0) {
        //注册成功回到首页or登录页
        //return "redirect:http://auth.mall/com/login.html";
        return "redirect:http://auth.mall.com/login.html"; //因为我们在本项目的config/MallWebConfig里配置了,故本服务内跳转可以直接这样写
      } else {
        //数据库中 用户名 或 手机号 已经有存在了
        Map<String, String> errors = new HashMap<>();
        errors.put("msg", r.getData("msg", new TypeReference<String>(){}));
        redirectAttributes.addFlashAttribute("errors", errors);
        return "redirect:http://auth.mall.com/reg.html";
      }

    } else {
      Map<String, String> erros = new HashMap<>();
      erros.put("code", "验证码错误");
      redirectAttributes.addFlashAttribute("errors", erros);

      return "redirect:http://auth.mall.com/reg.html";
    }
  }

  @PostMapping("/login")
  public String login(UserLoginVo vo/*因为我们是表单提交,所以不写@RequestParam(?)*/, RedirectAttributes redirectAttributes, HttpSession session){

    R login = memberFeignService.login(vo);
    if (login.getCode() == 0) {
      //成功
      System.out.println("登录成功~~~~~~~~~~~~");
      MemberRespVo data = login.getData("data", new TypeReference<MemberRespVo>() {});
      session.setAttribute(AuthServerConstant.LOGIN_USER, data);
      return "redirect:http://mall.com";
    } else {
      //失败
      Map<String, String> errors = new HashMap<>();
      errors.put("msg", login.getData("msg", new TypeReference<String>(){}));
      redirectAttributes.addFlashAttribute("errors", errors);
      return "redirect:http://auth.mall.com/login.html";
    }
  }

  @GetMapping("/login.html")
  public String loginPage(HttpSession session) {
    Object attribute = session.getAttribute(AuthServerConstant.LOGIN_USER);
    if (attribute == null) {
      //没登录
      return "login";
    }else{
      return "redirect:http://mall.com";
    }
  }
}
